﻿
namespace TransportAnalizer.AppTests.UnitTests
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Data;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    using TransportAnalizer_2._0.ViewModels;
    using TransportAnalizer_2._0.Model;
    using TransportAnalizer.DataTests;
    using TransportAnalizer.HelpClasses;


    [TestClass]
    public class NodeTypeViewModelTests
    {
        private Mock<IBusinessContextFactory> mock;
        private List<NodeType> store;

        [TestInitialize]
        public void TestInitialize()
        {
            store = new List<NodeType>();

            mock = new Mock<IBusinessContextFactory>();
            mock.Setup(m => m.GetNodeTypeBusinessContext.GetNodeTypeList()).Returns(store);
            mock.Setup(m => m.GetNodeTypeBusinessContext.CreateNodeType(It.IsAny<NodeType>())).Callback<NodeType>(nodeType => store.Add(nodeType));
            mock.Setup(m => m.GetNodeTypeBusinessContext.DeleteNodeType(It.IsAny<NodeType>())).Callback<NodeType>(nodeType => store.Remove(nodeType));
            mock.Setup(m => m.GetNodeTypeBusinessContext.UpdateNodeType(It.IsAny<NodeType>())).Callback<NodeType>(nodeType =>
            {
                int i = store.IndexOf(nodeType);
                store[i] = nodeType;
            });
        }

        [TestMethod]
        public void IsViewModel()
        {
            Assert.IsTrue(typeof(NodeTypeViewModel).BaseType == typeof(ViewModel));
        }

        [TestMethod]
        public void AddCommand_CannotExecuteWhenNameIsNotValid()
        {
            var viewModel = new NodeTypeViewModel(mock.Object)
            {
                SelectedNodeType = new NodeType
                {
                    Name = null,
                    Description = "description",
                    Passage=30,
                    Regulation=RegulationType.NoRegulation
                }
            };

            Assert.IsFalse(viewModel.AddCommand.CanExecute(null));
        }

        [TestMethod]
        public void AddCommand_CannotExecuteWhenDescriptionIsNotValid()
        {
            var viewModel = new NodeTypeViewModel(mock.Object)
            {
                SelectedNodeType = new NodeType
                {
                    Name = "1",
                    Passage=30,
                    Regulation=RegulationType.NoRegulation
                
                }
            };

            Assert.IsFalse(viewModel.AddCommand.CanExecute(null));
        }


        [TestMethod]
        public void AddCommand_AddsNodeTypeToNodeTypesCollectionWhenExecutedSuccessfully()
        {
            var viewModel = new NodeTypeViewModel(mock.Object)
            {
                SelectedNodeType = new NodeType
                {
                    Name = "1",
                    Description = "description",
                    Passage = 30,
                    Regulation = RegulationType.NoRegulation
                }
            };

            viewModel.AddCommand.Execute(null);

            Assert.IsTrue(viewModel.NodeTypes.Count == 1);
        }

        [TestMethod]
        public void CanModify_ShouldEqualFalseWhenSelectedNodeTypeIsNull()
        {
            var viewModel = new NodeTypeViewModel(mock.Object) { SelectedNodeType = null };
            Assert.IsFalse(viewModel.CanModify);
        }

        [TestMethod]
        public void CanModify_ShouldEqualTrueWhenSelectedNodeTypeIsNotNull()
        {
            var viewModel = new NodeTypeViewModel(mock.Object) { SelectedNodeType = new NodeType() };
            Assert.IsTrue(viewModel.CanModify);
        }

        [TestMethod]
        public void GetNodeTypeListCommand_PopulatesNodeTypesPropertyWithExpectedCollectionFromDataStore()
        {
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "1", Regulation = RegulationType.Stop, Passage = 30, Description = "описание1" });
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "2", Regulation = RegulationType.GiveWay, Passage = 40, Description = "описание2" });
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "3", Regulation = RegulationType.TrafficLight, Passage = 20, Description = "описание3" });

            var viewModel = new NodeTypeViewModel(mock.Object);

            viewModel.GetNodeTypeListCommand.Execute(null);

            Assert.IsTrue(viewModel.NodeTypes.Count == 3);

            // Use CollectionAssert by overriding Equals in entities
            // or using IComparer in CollectionAssert for a more full-proof
            // solution
        }

        [TestMethod]
        public void GetNodeTypeListCommand_SelectedNodeTypeIsSetToNullWhenExecuted()
        {
            var viewModel = new NodeTypeViewModel(mock.Object)
            {
                SelectedNodeType = new NodeType
                {
                    Name = "1",
                    Description = "description",
                    Passage = 30,
                    Regulation = RegulationType.NoRegulation
                }
            };

            viewModel.GetNodeTypeListCommand.Execute(null);

            Assert.IsNull(viewModel.SelectedNodeType);
        }

        [TestMethod]
        public void SaveCommand_InvokesIBusinessContextUpdateNodeTypeMethod()
        {
            // Arrange
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "1", Regulation = RegulationType.Stop, Passage = 30, Description = "описание1" });

            var viewModel = new NodeTypeViewModel(mock.Object);

            viewModel.GetNodeTypeListCommand.Execute(null);
            viewModel.SelectedNodeType = viewModel.NodeTypes.First();

            // Act
            viewModel.UpdateCommand.Execute(null);

            // Assert
            mock.Verify(m => m.GetNodeTypeBusinessContext.UpdateNodeType(It.IsAny<NodeType>()), Times.Once);
        }

        [TestMethod]
        public void DeleteCommand_InvokesIBusinessContextDeleteNodeTypeMethod()
        {
            // Arrange
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "1", Regulation = RegulationType.Stop, Passage = 30, Description = "описание1" });

            var viewModel = new NodeTypeViewModel(mock.Object);

            viewModel.GetNodeTypeListCommand.Execute(null);
            viewModel.SelectedNodeType = viewModel.NodeTypes.First();

            // Act
            viewModel.DeleteCommand.Execute(null);

            // Assert
            mock.Verify(m => m.GetNodeTypeBusinessContext.DeleteNodeType(It.IsAny<NodeType>()), Times.Once);
        }

        [TestMethod]
        public void DeleteCommand_SelectedNodeTypeIsSetToNull()
        {
            // Arrange
            mock.Object.GetNodeTypeBusinessContext.CreateNodeType(new NodeType { Name = "1", Regulation = RegulationType.Stop, Passage = 30, Description = "описание1" });

            var viewModel = new NodeTypeViewModel(mock.Object);

            viewModel.GetNodeTypeListCommand.Execute(null);
            viewModel.SelectedNodeType = viewModel.NodeTypes.First();

            // Act
            viewModel.DeleteCommand.Execute(null);

            // Assert
            Assert.IsNull(viewModel.SelectedNodeType);
        }

        [TestMethod]
        public void PropertyChanged_IsRaisedForCanModifyWhenSelectedNodeTypePropertyHasChanged()
        {
            var viewModel = new NodeTypeViewModel(mock.Object);

            bool eventRaised = false;

            viewModel.PropertyChanged += (sender, e) =>
            {
                if (e.PropertyName == "CanModify")
                    eventRaised = true;
            };

            viewModel.SelectedNodeType = null;

            Assert.IsTrue(eventRaised);
        }

        [TestMethod]
        public void PropertyChanged_IsRaisedForSelectedNodeTypeWhenSelectedNodeTypePropertyHasChanged()
        {
            var viewModel = new NodeTypeViewModel(mock.Object);

            bool eventRaised = false;

            viewModel.PropertyChanged += (sender, e) =>
            {
                if (e.PropertyName == "SelectedNodeType")
                    eventRaised = true;
            };

            viewModel.SelectedNodeType = null;

            Assert.IsTrue(eventRaised);
        }
    }
}
